package com.meaningful.thinking.netty_demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class NettyServer {

    public static void main(String[] args) {
        Map<Channel, List<String>> DB = new ConcurrentHashMap<>();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup());
        serverBootstrap.channel(NioServerSocketChannel.class);
        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline()
                        .addLast(new LineBasedFrameDecoder(1024))
                        .addLast(new StringDecoder())
                        .addLast(new StringEncoder())
                        .addLast(new SimpleChannelInboundHandler<String>() {

                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                System.out.println(msg);

                                // 返回给客户端
                                String message = msg + "world\n";
                                // 给出栈处理器数据
                                ctx.channel().writeAndFlush(message);

                                ctx.fireChannelRead(msg);
                            }

                        })
                        .addLast(new SimpleChannelInboundHandler<String>() {

                            @Override
                            protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
                                List<String> msgList = DB.computeIfAbsent(ctx.channel(), channel -> new ArrayList<>());
                                msgList.add(msg);
                            }

                            @Override
                            public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                                super.channelRegistered(ctx);
                                System.out.println(ctx.channel() + "注册了");
                            }

                            @Override
                            public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
                                super.channelUnregistered(ctx);
                                System.out.println(ctx.channel() + "解除注册了");
                            }

                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                super.channelActive(ctx);
                                System.out.println(ctx.channel() + "可以使用了");
                            }

                            @Override
                            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                super.channelInactive(ctx);
                                List<String> strings = DB.get(ctx.channel());
                                System.out.println(strings);
                            }

                            @Override
                            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                if (cause instanceof SocketException socketException) {
                                    if ("Connection reset".equals(socketException.getMessage())) {
                                        System.err.println("客户端意外断开连接");
                                    } else {
                                        ctx.fireExceptionCaught(cause);
                                    }
                                } else {
                                    ctx.fireExceptionCaught(cause);
                                }
                            }

                        });
            }

        });
        ChannelFuture bindFuture = serverBootstrap.bind(8080);
        bindFuture.addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("服务器成功监听" + 8080);
            } else {
                System.out.println("服务器监听失败");
            }
        });
    }

}
